﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using EntityFrameworkContrib.PostSharp4EF;
using System.Runtime.Serialization;
using CyclicReferences.Public;
using System.Data.Objects;
using System.Collections;

namespace EFContrib.PS4EF.Tst.SchoolTests
{
    /// <summary>
    /// integration tests
    /// </summary>
    [TestClass]
    public class SchoolTests
    {
        #region setup
        public SchoolTests()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion 
        #endregion

        [TestMethod]
        public void testSchoolSimpleFirstNameUpdateModel()
        {
            string MsgOnWire = string.Empty;

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                Person kim = (from p in context.Person
                                 where p.PersonID == 1
                                 select p).First();

                MsgOnWire = context.Serialize(kim);
            }


            // deserialize
            PersonClient kimClient = MsgOnWire.DeserializeForClient<PersonClient>();
            kimClient.FirstName = "KimChangedAt" + DateTime.Now.ToString();
            string stringToCheck = kimClient.FirstName;

            // serialize
            MsgOnWire = kimClient.SerializeForClient();

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                Person kim = context.Deserialize<Person>(MsgOnWire);

                context.SaveChanges();
            }


            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                Person kim = (from p in context.Person
                              where p.PersonID == 1
                              select p).First();

                Assert.IsTrue(stringToCheck == kim.FirstName);
            }

        }


        [TestMethod]
        public void testSchoolAddExistingCourse()
        {
            string PersonOnWire, CoursesOnWire, DepartmentsOnWire = string.Empty;

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
               List<Course> allcourses = context.Course.ToList();

               List<Department> alldepartments = context.Department.ToList();

               Person kim = (from p in context.Person.Include("Courses")
                              where p.PersonID == 1
                              select p).First();



               PersonOnWire = context.Serialize(kim);
               CoursesOnWire = context.Serialize(allcourses);
               DepartmentsOnWire = context.Serialize(alldepartments);
            }

            // deserialize
            PersonClient kimClient = PersonOnWire.DeserializeForClient<PersonClient>();
            List<CourseClient> courses = CoursesOnWire.DeserializeForClient<List<CourseClient>>();
            List<DepartmentClient> departments = DepartmentsOnWire.DeserializeForClient<List<DepartmentClient>>();

            // add new course
            CourseClient Quantitative = courses[8]; //courses.Find(c => c.CourseID == 4061);
            Quantitative.SerializeForClient();
            kimClient.Courses.Add(Quantitative);
            Quantitative.Persons.Add(kimClient);


            // serialize
            PersonOnWire = kimClient.SerializeForClient();

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                Person kim = context.Deserialize<Person>(PersonOnWire);

                context.SaveChanges();

                kim.Courses.Remove(kim.Courses.ToList()[1]);

                context.SaveChanges();
            }
        }

        [TestMethod]
        public void testSchoolUpdateCourse()
        {
            string PersonOnWire, CoursesOnWire, DepartmentsOnWire = string.Empty;

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                List<Course> allcourses = context.Course.ToList();

                List<Department> alldepartments = context.Department.ToList();

                Person kim = (from p in context.Person.Include("Courses")
                              where p.PersonID == 1
                              select p).First();



                PersonOnWire = context.Serialize(kim);
                CoursesOnWire = context.Serialize(allcourses);
                DepartmentsOnWire = context.Serialize(alldepartments);
            }

            // deserialize
            PersonClient kimClient = PersonOnWire.DeserializeForClient<PersonClient>();
            List<CourseClient> courses = CoursesOnWire.DeserializeForClient<List<CourseClient>>();
            List<DepartmentClient> departments = DepartmentsOnWire.DeserializeForClient<List<DepartmentClient>>();

            CourseClient course = kimClient.Courses.First();
            string origname = course.Title;

            course.Title = "Changed";

            // serialize
            PersonOnWire = kimClient.SerializeForClient();

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                Person kim = context.Deserialize<Person>(PersonOnWire);

                context.SaveChanges();

                kim.Courses.First().Title = origname;

                context.SaveChanges();
            }
        }

        [TestMethod]
        public void testSchoolAddAndDeleteNewCourse()
        {
            string PersonOnWire, CoursesOnWire, DepartmentsOnWire = string.Empty;

            #region adding a course
            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                List<Course> allcourses = context.Course.ToList();

                List<Department> alldepartments = context.Department.ToList();

                Person kim = (from p in context.Person.Include("Courses")
                              where p.PersonID == 1
                              select p).First();

                PersonOnWire = context.Serialize(kim);
                CoursesOnWire = context.Serialize(allcourses);
                DepartmentsOnWire = context.Serialize(alldepartments);
            }

            // deserialize
            PersonClient kimClient = PersonOnWire.DeserializeForClient<PersonClient>();
            List<CourseClient> courses = CoursesOnWire.DeserializeForClient<List<CourseClient>>();
            List<DepartmentClient> departments = DepartmentsOnWire.DeserializeForClient<List<DepartmentClient>>();

            CourseClient newCourse = new CourseClient { CourseID=1, Time = DateTime.Now, Title = "NewCourse", Location = "Somewhere", Days = "T", Credits = 4 };
            newCourse.Persons = new List<PersonClient>();
            newCourse.Enrollments = new List<EnrollmentClient>();

            kimClient.Courses.Add(newCourse);
            newCourse.Persons.Add(kimClient);
            DepartmentClient dep = departments.First();
            dep.Courses.Add(newCourse);
            newCourse.Department = dep;


            // serialize
            PersonOnWire = kimClient.SerializeForClient();

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                Person kim = context.Deserialize<Person>(PersonOnWire);

                context.SaveChanges();
            } 
            #endregion

            #region deleting a course
            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                List<Course> allcourses = context.Course.ToList();

                List<Department> alldepartments = context.Department.ToList();

                Person kim = (from p in context.Person.Include("Courses")
                              where p.PersonID == 1
                              select p).First();

                PersonOnWire = context.Serialize(kim);
                CoursesOnWire = context.Serialize(allcourses);
                DepartmentsOnWire = context.Serialize(alldepartments);
            }

            // deserialize
            kimClient = PersonOnWire.DeserializeForClient<PersonClient>();
            courses = CoursesOnWire.DeserializeForClient<List<CourseClient>>();
            departments = DepartmentsOnWire.DeserializeForClient<List<DepartmentClient>>();

            
            CourseClient addedCourse = kimClient.Courses.First();
            kimClient.Courses.Remove(addedCourse);
            addedCourse.Persons.Remove(kimClient);

            // serialize
            PersonOnWire = kimClient.SerializeForClient();

            using (SchoolEntitiesConnection context = new SchoolEntitiesConnection())
            {
                Person kim = context.Deserialize<Person>(PersonOnWire);

                context.SaveChanges();
            }
            #endregion

        }

    }

            #region extensions for serializing
		    public static class SerializeHelp
    {
        public static string Serialize(this ObjectContext context, object graphroot)
        {
            ((IContextAware)graphroot).CreateSerializableState(context);

            DataContractSerializer s = new DataContractSerializer(graphroot.GetType(), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
            return s.GetWellFormedToContract(graphroot);
        }

        public static string Serialize(this ObjectContext context, IList listOfObjects)
        {
            foreach(object item in listOfObjects)
                ((IContextAware)item).CreateSerializableState(context);

            DataContractSerializer s = new DataContractSerializer(listOfObjects.GetType(), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
            return s.GetWellFormedToContract(listOfObjects);
        }

        public static T Deserialize<T>(this ObjectContext context, string msg)
        {
            DataContractSerializer s = new DataContractSerializer(typeof(T), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());
            T p = (T)s.UnwrapFromString(msg);

            ((IContextAware)p).AttachGraphToContext(context, source => source.GetType().Name);

            return p;

        }

        public static T DeserializeForClient<T>(this string msg)
        {
            DataContractSerializer s = new DataContractSerializer(typeof(T), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());

            return (T)s.UnwrapFromString(msg);
        }

        public static string SerializeForClient(this object p)
        {
            DataContractSerializer s = new DataContractSerializer(p.GetType(), null, int.MaxValue, false, false, new SubstituteDomainDataContractSurrogate());

            return s.GetWellFormedToContract(p);
        }
    }

	        #endregion
}
